﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PhraseCorrector.SpellLook
{
    /// <summary>
    /// 一个故意不透明的类，用于在添加大量单词时临时存储字典数据。
    /// 通过在构建字典数据期间暂存数据，可以显著节省时间并减少最终内存使用。
    /// </summary>
    public class SuggestionStage
    {

        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 定义一个节点结构，用于存储建议和指向下一个节点的指针。
        /// </summary>
        private struct Node
        {
            public string suggestion; // 存储建议字符串。
            public int next; // 指向下一个节点的索引。
        }

        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 定义一个条目结构，用于存储删除建议的计数和第一个节点的索引。
        /// </summary>
        private struct Entry
        {
            public int count; // 删除建议的总数。
            public int first; // 第一个节点的索引。
        }

        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 定义一个字典，用于存储删除哈希值和对应的条目。
        /// </summary>
        private Dictionary<int, Entry> Deletes { get; set; }
        // 定义一个分块数组，用于存储节点。
        private ChunkArray<Node> Nodes { get; set; }

        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 创建一个新的 SuggestionStage 实例。
        /// </summary>
        /// <remarks>
        /// 指定准确的 initialCapacity 并不是必需的，
        /// 但它可以通过避免数据结构调整来加快处理速度。
        /// </remarks>
        /// <param name="initialCapacity">预期将添加的单词数量。</param>
        public SuggestionStage(int initialCapacity)
        {
            Deletes= new Dictionary<int, Entry>(initialCapacity);
            Nodes= new ChunkArray<Node>(initialCapacity * 2);
        }

        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 获取删除词的唯一计数。
        /// </summary>
        public int DeleteCount { get { return Deletes.Count; } }

        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 获取所有删除项的所有建议总数。
        /// </summary>
        public int NodeCount { get { return Nodes.Count; } }

        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 清除 SuggestionStaging 中的所有数据。
        /// </summary>
        public void Clear()
        {
            Deletes.Clear();
            Nodes.Clear();
        }

        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 添加一个建议到指定的删除哈希值。
        /// </summary>
        /// <param name="deleteHash">删除哈希值。</param>
        /// <param name="suggestion">建议字符串。</param>
        internal void Add(int deleteHash, string suggestion)
        {
            if (!Deletes.TryGetValue(deleteHash, out Entry entry))
                entry= new Entry { count= 0, first= -1 };
            int next= entry.first;
            entry.count++;
            entry.first= Nodes.Count;
            Deletes[deleteHash]= entry;
            Nodes.Add(new Node { suggestion= suggestion, next= next });
        }

        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 将暂存的数据提交到永久删除字典。
        /// </summary>
        /// <param name="permanentDeletes">永久删除字典。</param>
        internal void CommitTo(Dictionary<int, string[]> permanentDeletes)
        {
            foreach (var keyPair in Deletes)
            {
                int i;
                if (permanentDeletes.TryGetValue(keyPair.Key, out string[] suggestions))
                {
                    i= suggestions.Length;
                    var newSuggestions= new string[suggestions.Length + keyPair.Value.count];
                    Array.Copy(suggestions, newSuggestions, suggestions.Length);
                    permanentDeletes[keyPair.Key]= suggestions= newSuggestions;
                }
                else
                {
                    i= 0;
                    suggestions= new string[keyPair.Value.count];
                    permanentDeletes.Add(keyPair.Key, suggestions);
                }
                int next= keyPair.Value.first;
                while (next >= 0)
                {
                    var node= Nodes[next];
                    suggestions[i]= node.suggestion;
                    next= node.next;
                    i++;
                }
            }
        }
    }
}
